﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace JH
{
    /// <summary>
    /// 固定长度排序列表，元素始终保持有序。
    /// 集合元素保持唯一。
    /// </summary>
    public class FixedSortUniqueArray<T> : IFixedContainer<T>
    {
        /// <summary>
        ///  溢出模式
        /// </summary>
        public OverflowMode Mode { get; }

        /// <summary>
        /// 排序比较器
        /// </summary>
        private readonly IComparer<T> _sortComparer;

        /// <summary>
        /// 固定长度的唯一集合，用于去重和管理固定容量；
        /// 同时会保持原有的插入顺序，以确保可以始终获取到最早添加的元素；
        /// </summary>
        private readonly FixUniqueArray<T> _fixedHashSet;

        /// <summary>
        /// 排序后的元素列表
        /// </summary>
        private readonly List<T> _sorted;

        /// <summary>
        /// 获取集合中的总元素数量。
        /// </summary>
        public int Count => _fixedHashSet.Count;

        /// <summary>
        ///  获取集合是否只读。
        /// </summary>
        public bool IsReadOnly => false;

        /// <summary>
        /// 获取集合的容量限制。
        /// </summary>
        public int MaxSize => _fixedHashSet.MaxSize;

        /// <summary>
        ///  当元素因为存储容量满了，添加新元素而被丢弃时触发
        /// </summary>
        public event Action<T> OnItemDiscard;

        /// <summary>
        /// 创建一个固定长度排序哈希集合。
        /// </summary>
        public FixedSortUniqueArray(int maxSize, IEqualityComparer<T> equalityComparer = null,
            IComparer<T> sortComparer = null, OverflowMode mode = OverflowMode.DiscardOldestAdd)
        {
            // 设置溢出模式
            Mode = mode;

            // 初始化排序比较器
            _sortComparer = sortComparer ?? Comparer<T>.Default;

            // 初始化底层哈希集合
            _fixedHashSet = new FixUniqueArray<T>(maxSize, equalityComparer, mode);

            // 初始化排序后的元素列表
            _sorted = new List<T>(maxSize);
        }

        /// <summary>
        ///  添加元素到集合中，并保持集合的有序性。如果集合已经存在，则直接返回
        /// </summary>
        public void Add(T item)
        {
            // 如果元素已经存在于集合中，则不添加
            if (_fixedHashSet.Contains(item)) return;

            // 处理容量溢出
            this.HandleOverflow();

            // 插入到哈希集合中
            _fixedHashSet.Add(item);

            // 插入到排序列表中
            BinaryInsert(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            // 将排序后的元素复制到数组中
            _sorted.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// 移除指定元素。
        /// </summary>
        public bool Remove(T item)
        {
            // 从哈希集合中移除元素
            var ret = _fixedHashSet.Remove(item);

            // 从排序列表中移除
            if (ret) BinaryRemove(item);
            return ret;
        }

        /// <summary>
        /// 查找元素在集合中的索引。
        /// </summary>
        public int FindIndex(T item)
        {
            // 使用二分查找找到元素的索引
            int index = _sorted.BinarySearch(item, _sortComparer);
            return index >= 0 ? index : -1;
        }

        /// <summary>
        /// 判断集合是否包含指定元素。
        /// </summary>
        public bool Contains(T item)
        {
            return _fixedHashSet.Contains(item);
        }

        /// <summary>
        /// 清空集合中的所有元素。
        /// </summary>
        public void Clear()
        {
            _fixedHashSet.Clear();
            _sorted.Clear();
        }

        public int IndexOf(T item)
        {
            // 使用二分查找找到元素的索引
            int index = _sorted.BinarySearch(item, _sortComparer);
            return index >= 0 ? index : -1;
        }

        /// <summary>
        ///  如果数据已经存在，将直接返回
        /// </summary>
        /// <remarks>有序列表的插入将退化为Add方法</remarks>
        public void Insert(int index, T item)
        {
            // 插入到哈希集合中
            Add(item);
        }

        public void RemoveAt(int index)
        {
            if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException(nameof(index), "索引超出范围！");

            //移除元素
            Remove(_sorted[index]);
        }

        /// <summary>
        /// 获取排序后的集合中的元素。
        /// </summary>
        public T this[int index]
        {
            get
            {
                if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException(nameof(index), "索引超出范围！");
                return _sorted[index];
            }
            set => Insert(index, value);
        }

        /// <summary>
        /// 返回排序后的元素枚举器。
        /// </summary>
        public IEnumerator<T> GetEnumerator()
        {
            return _sorted.GetEnumerator();
        }

        /// <summary>
        /// 二分查找插入元素到排序列表中。
        /// </summary>
        private void BinaryInsert(T item)
        {
            // 使用二分查找找到插入位置
            int index = _sorted.BinarySearch(item, _sortComparer);
            if (index < 0) index = ~index; // 如果没有找到，获取插入位置

            // 插入元素到正确的位置
            _sorted.Insert(index, item);
        }

        /// <summary>
        /// 二分查找移除元素。
        /// </summary>
        private void BinaryRemove(T item)
        {
            // 使用二分查找找到元素的索引
            int index = _sorted.BinarySearch(item, _sortComparer);
            if (index >= 0) _sorted.RemoveAt(index); // 从排序列表中移除
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        /// <summary>
        ///  根据溢出行为枚举，获取需要丢弃的元素
        /// </summary>
        T IFixedContainer<T>.GetDiscardItem()
        {
            return Mode switch
            {
                OverflowMode.DiscardFirst => _sorted[0],
                OverflowMode.DiscardOldestAdd => _fixedHashSet[0],
                OverflowMode.DiscardNewestAdd => _fixedHashSet[^1],
                OverflowMode.DiscardLast => _sorted[^1],
                _ => throw new ArgumentOutOfRangeException()
            };
        }

        /// <summary>
        ///  引发丢弃事件
        /// </summary>
        void IFixedContainer<T>.InvokeEvent(T item)
        {
            OnItemDiscard?.Invoke(item);
        }
    }
}